package com.carleasoft.mps.adu.business.position.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carleasoft.mps.adu.business.position.bean.entity.AuthorityPositionEntity;
import com.carleasoft.mps.adu.business.position.bean.entity.AuthorityPositionGroupEntity;
import com.carleasoft.mps.adu.business.position.bean.po.AuthorityPositionGroupPagePo;
import com.carleasoft.mps.adu.business.position.bean.po.AuthorityPositionGroupPo;
import com.carleasoft.mps.adu.business.position.bean.vo.GroupPositionVo;
import com.carleasoft.mps.adu.business.position.bean.vo.PositionGroupVo;
import com.carleasoft.mps.adu.business.position.dao.AuthorityPositionDao;
import com.carleasoft.mps.adu.business.position.dao.AuthorityPositionGroupDao;
import com.carleasoft.mps.adu.business.position.service.AuthorityPositionGroupService;
import com.carleasoft.mps.adu.business.position.service.AuthorityPositionService;
import com.carleasoft.mps.adu.common.constants.BusinessErrorEnum;
import com.carleasoft.mps.core.exceptions.BusinessException;
import com.carleasoft.mps.core.user.Constants;
import com.carleasoft.mps.core.user.SortPo;
import com.carleasoft.mps.core.utils.DateUtil;
import com.carleasoft.mps.core.utils.ExceptionUtil;
import com.carleasoft.mps.security.permission.data.RequiresDataPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.carleasoft.mps.adu.common.constants.BusinessErrorEnum.*;
import static java.util.stream.Collectors.toList;

/**
 * <p>Description: positionGroup serviceImpl</p>
 *
 * @author ztm
 * @since 2020-05-12
 */
@Service
public class AuthorityPositionGroupServiceImpl extends ServiceImpl<AuthorityPositionGroupDao, AuthorityPositionGroupEntity> implements AuthorityPositionGroupService {
    @Autowired
    AuthorityPositionService authorityPositionService;
    @Autowired
    AuthorityPositionGroupDao authorityPositionGroupDao;
    @Autowired
    AuthorityPositionDao authorityPositionDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AuthorityPositionGroupEntity add(AuthorityPositionGroupPo authorityPositionGroupPo) {

        AuthorityPositionGroupEntity groupEntity = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery()
                .eq(AuthorityPositionGroupEntity::getPositionGroupName, authorityPositionGroupPo.getPositionGroupName())
                .eq(AuthorityPositionGroupEntity::getParentPositionGroupCode, authorityPositionGroupPo.getParentPositionGroupCode()));
        if (Objects.nonNull(groupEntity)) {
            // 职位名称重复返回
            throw new BusinessException(DUPLICATE_POSITION_GROUP);
        }
        if (StrUtil.isNotBlank(authorityPositionGroupPo.getPositionGroupNumber()) && Objects.nonNull(this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery()
                .eq(AuthorityPositionGroupEntity::getPositionGroupNumber, authorityPositionGroupPo.getPositionGroupNumber()).eq(AuthorityPositionGroupEntity::getDeptCode, authorityPositionGroupPo.getDeptCode())))) {
            // 职位编号重复返回
            throw new BusinessException(DUPLICATE_NUMBER_GROUP);
        }
        AuthorityPositionGroupEntity authorityPositionGroupEntity = BeanUtil.copyProperties(authorityPositionGroupPo, AuthorityPositionGroupEntity.class);

        if (StrUtil.isBlank(authorityPositionGroupPo.getPositionGroupCode())) {
            String code = IdWorker.getIdStr();
            authorityPositionGroupEntity.setPositionGroupCode(code);
        }
        //默认部门添加过来，不设置父code
        if (StrUtil.isBlank(authorityPositionGroupPo.getParentPositionGroupCode())) {
            authorityPositionGroupEntity.setParentPositionGroupCode(Constants.PARENT_CODE);
            authorityPositionGroupEntity.setPositionGroupName(authorityPositionGroupEntity.getPositionGroupName()+Constants.POS_SUFFIX);
            authorityPositionGroupEntity.setFullPath(authorityPositionGroupEntity.getPositionGroupCode());
        }
        else {
            AuthorityPositionGroupEntity parent = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupEntity.getParentPositionGroupCode()));
            authorityPositionGroupEntity.setDeptCode(parent.getDeptCode());
            authorityPositionGroupEntity.setFullPath(parent.getFullPath() + Constants.DELIMITER + authorityPositionGroupEntity.getPositionGroupCode());
        }
        if (Objects.isNull(authorityPositionGroupPo.getSort())) {
            AuthorityPositionGroupEntity sortType = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery()
                    .eq(AuthorityPositionGroupEntity::getParentPositionGroupCode, authorityPositionGroupPo.getParentPositionGroupCode())
                    .orderByDesc(AuthorityPositionGroupEntity::getSort).last("limit 1"));
            authorityPositionGroupEntity.setSort(Objects.isNull(sortType) ? 1 : sortType.getSort() + 1);
        }
        this.save(authorityPositionGroupEntity);

        return authorityPositionGroupEntity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AuthorityPositionGroupEntity update(AuthorityPositionGroupPo authorityPositionGroupPo) {
        int count = this.count(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery()
                .eq(AuthorityPositionGroupEntity::getPositionGroupName, authorityPositionGroupPo.getPositionGroupName())
                .eq(AuthorityPositionGroupEntity::getParentPositionGroupCode,authorityPositionGroupPo.getParentPositionGroupCode())
                .ne(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupPo.getPositionGroupCode()));
        if (count > 0) {
            throw ExceptionUtil.create(DEPT_NAME_REPEAT);
        }
        if (StrUtil.isNotBlank(authorityPositionGroupPo.getPositionGroupNumber()) && Objects.nonNull(this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery()
                .eq(AuthorityPositionGroupEntity::getPositionGroupNumber, authorityPositionGroupPo.getPositionGroupNumber())
                .eq(AuthorityPositionGroupEntity::getParentPositionGroupCode,authorityPositionGroupPo.getParentPositionGroupCode())
                .ne(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupPo.getPositionGroupCode())))) {
            // 职位名称重复返回
            throw new BusinessException(DUPLICATE_NUMBER_GROUP);
        }
        AuthorityPositionGroupEntity current = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupPo.getPositionGroupCode()));
        if(current.getPositionGroupName().contains(Constants.POS_SUFFIX)){
            current.setPositionGroupName(authorityPositionGroupPo.getPositionGroupName()+Constants.POS_SUFFIX);
        }else {
            current.setPositionGroupName(authorityPositionGroupPo.getPositionGroupName());
        }

        current.setRemark(authorityPositionGroupPo.getRemark());
        current.setPositionGroupNumber(authorityPositionGroupPo.getPositionGroupNumber());
        current.setRemark(authorityPositionGroupPo.getRemark());
        //此处可能会产生脏读或幻读情况
        if(!current.getDeptCode().equals(authorityPositionGroupPo.getDeptCode())){
            //把所有子分组的所属部门统一更新为新的部门
            this.authorityPositionGroupDao.batchUpdateDeptCode(authorityPositionGroupPo.getDeptCode(),current.getFullPath());
            //更改职务的部门冗余字段
            this.authorityPositionDao.batchUpdateDeptCode(authorityPositionGroupPo.getDeptCode(),current.getFullPath());
            current.setDeptCode(authorityPositionGroupPo.getDeptCode());
        }

        //判断是否改变父亲节点
        if (StrUtil.isNotBlank(authorityPositionGroupPo.getParentPositionGroupCode()) && current.getParentPositionGroupCode().equals(authorityPositionGroupPo.getParentPositionGroupCode())) {
            this.update(current, Wrappers.<AuthorityPositionGroupEntity>lambdaUpdate().eq(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupPo.getPositionGroupCode()));
        }
        else if (StrUtil.isBlank(authorityPositionGroupPo.getParentPositionGroupCode()) && current.getParentPositionGroupCode().equals(Constants.PARENT_CODE)) {
            this.update(current, Wrappers.<AuthorityPositionGroupEntity>lambdaUpdate().eq(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupPo.getPositionGroupCode()));
        } else {
            //判断是否改为了顶级
            if (StrUtil.isNotBlank(authorityPositionGroupPo.getParentPositionGroupCode())) {
                //得到上级分类的详细信息
                AuthorityPositionGroupEntity parent = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupPo.getParentPositionGroupCode()));
                //全路径拼接
                String searchChar = current.getFullPath();
                String newChar = parent.getFullPath() + Constants.DELIMITER + authorityPositionGroupPo.getPositionGroupCode();
                current.setFullPath(newChar);
                this.authorityPositionGroupDao.batchUpdateFullPath(searchChar, newChar);

            } else {
                String searchChar = current.getFullPath();
                String newChar = authorityPositionGroupPo.getDeptCode() + Constants.DELIMITER + authorityPositionGroupPo.getPositionGroupCode();
                current.setFullPath(newChar);
                this.authorityPositionGroupDao.batchUpdateFullPath(searchChar, newChar);
            }
            current.setParentPositionGroupCode(authorityPositionGroupPo.getParentPositionGroupCode());
            AuthorityPositionGroupEntity sortType = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery()
                    .eq(AuthorityPositionGroupEntity::getDeptCode, current.getParentPositionGroupCode())
                    .orderByDesc(AuthorityPositionGroupEntity::getSort).last("limit 1"));
            current.setSort(Objects.isNull(sortType) ? 1 : sortType.getSort() + 1);
            this.update(current, Wrappers.<AuthorityPositionGroupEntity>lambdaUpdate().eq(AuthorityPositionGroupEntity::getPositionGroupCode, authorityPositionGroupPo.getPositionGroupCode()));
        }

        return current;
    }

    @Override
    @RequiresDataPermission(dataPerm = {@RequiresDataPermission.Scope(method = "pageQuery",scope = Constants.DATA_SCOPE_DEPT)})
    public Page doFindList(Page page, AuthorityPositionGroupPagePo authorityPositionGroupPo) {
        Page<PositionGroupVo> positionGroupVoPage = this.getBaseMapper().pageQuery(page, authorityPositionGroupPo,Constants.PARENT_CODE);
        return positionGroupVoPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByCode(String positionGroupCode) {

        int positionEntities = authorityPositionService.count(Wrappers.<AuthorityPositionEntity>lambdaQuery()
                .eq(AuthorityPositionEntity::getPositionGroupCode, positionGroupCode));
        if (positionEntities > 0) {
            throw new BusinessException((POSITION_CANNOT_BE_DELETED));
        }

        int positionGroupEntities = this.count(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getParentPositionGroupCode, positionGroupCode));

        if (positionGroupEntities > 0) {
            throw new BusinessException(POSITION_GROUP_CANNOT_SUB_DELETED);
        }
        return this.remove(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getPositionGroupCode, positionGroupCode));
    }

    /**
     * 排序修改接口(默认顶级部门,默认顶级职务分组的排序会一并修改)
     *
     * @param sortPo
     * @return
     */
    @Override
    public Boolean updateSort(SortPo sortPo) {
        boolean result = false;
        if (sortPo.getSort() == null) {
            //自己
            AuthorityPositionGroupEntity own = this.getById(sortPo.getOwnCode());
            Integer ownSort = own.getSort();
            Long ownSortDate = own.getSortDate();
            AuthorityPositionGroupEntity down = this.getById(sortPo.getMoveCode());
            Integer sort = down.getSort();
            Long sortDate = down.getSortDate();

            own.setSort(sort);
            own.setSortDate(sortDate);
            result = this.updateById(own);
            down.setSort(ownSort);
            down.setSortDate(ownSortDate);
            result = this.updateById(down);
        } else {
            LambdaUpdateWrapper<AuthorityPositionGroupEntity> wrapper = Wrappers.<AuthorityPositionGroupEntity>lambdaUpdate();
            wrapper.eq(AuthorityPositionGroupEntity::getId, sortPo.getOwnCode());
            wrapper.set(AuthorityPositionGroupEntity::getSortDate, DateUtil.getEpochSecond());
            wrapper.set(AuthorityPositionGroupEntity::getSort, sortPo.getSort());
            result = this.update(wrapper);
        }

        return result;

    }

    @Override
    @RequiresDataPermission(dataPerm = {@RequiresDataPermission.Scope(method = "treeList",scope = Constants.DATA_SCOPE_DEPT)})
    public List<PositionGroupVo> doFindTree(AuthorityPositionGroupPo authorityPositionGroupPo) {
        List<PositionGroupVo> positionGroupVos = this.authorityPositionGroupDao.treeList(authorityPositionGroupPo,Constants.PARENT_CODE);
        return this.buildTree(positionGroupVos);
    }

    @Override
    public GroupPositionVo doFindByCode(String positionGroupCode) {

        AuthorityPositionGroupEntity groupEntity = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getPositionGroupCode,positionGroupCode));
        GroupPositionVo positionVo = BeanUtil.copyProperties(groupEntity, GroupPositionVo.class);
        if(!groupEntity.getParentPositionGroupCode().equals(Constants.PARENT_CODE)) {
            AuthorityPositionGroupEntity parentEntity = this.getOne(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getPositionGroupCode, groupEntity.getParentPositionGroupCode()));
            positionVo.setParentPositionGroupName(parentEntity.getPositionGroupName());
        }
        return positionVo;
    }

    @Override
    public Boolean checkPositionGroup(AuthorityPositionGroupPo authorityPositionGroupPo) {
        int count = this.count(Wrappers.<AuthorityPositionGroupEntity>lambdaQuery().eq(AuthorityPositionGroupEntity::getPositionGroupName, authorityPositionGroupPo.getPositionGroupName()));
        if (count>0){
            return false;
        }
        return true;
    }


    //解析并找到父节点
    private List<PositionGroupVo> buildTree(List<PositionGroupVo> list) {
        //找出顶级节点编码
        Set<String> pList= list.stream().collect(Collectors.groupingBy(PositionGroupVo::getParentPositionGroupCode)).keySet();
        Set<String> cList= list.stream().collect(Collectors.groupingBy(PositionGroupVo::getPositionGroupCode)).keySet();
        List<String> topList = pList.stream().filter(item -> !cList.contains(item)).collect(toList());

        List<PositionGroupVo> last = new ArrayList<>();
        for (String parentCode : topList) {
            last.addAll(this.getTreeListFromCurrent(parentCode,list));
        }
        return last;
    }
    /**
     * 解析树形数据
     * @param currentId
     * @param entityList
     * @return
     */
    public List<PositionGroupVo> getTreeListFromCurrent(String currentId, List<PositionGroupVo> entityList) {

        if(entityList==null || entityList.size()==0) return new ArrayList<>();

        List<PositionGroupVo> resultList = new ArrayList<>();

        //获取顶层元素集合
        for (PositionGroupVo entity : entityList) {
            if(currentId.equals(entity.getParentPositionGroupCode())){
                resultList.add(entity);
            }
        }

        //获取每个顶层元素的子数据集合
        for (PositionGroupVo entity : resultList) {
            entity.setChildren(getSubList(entity.getPositionGroupCode(), entityList));
        }
        return resultList;
    }

    /**
     * 获取子数据集合
     * @param subCode
     * @param subList
     */
    private  List<PositionGroupVo> getSubList(String subCode, List<PositionGroupVo> subList) {
        List<PositionGroupVo> childList = new ArrayList<>();
        //子集的直接子对象
        for (PositionGroupVo entity : subList) {
            if(subCode.equals(entity.getParentPositionGroupCode())){
                childList.add(entity);
            }
        }

        //子集的间接子对象
        for (PositionGroupVo entity : childList) {
            entity.setChildren(getSubList(entity.getPositionGroupCode(), subList));
        }
        //递归退出条件
        if(childList.size() == 0){
            return null;
        }
        return childList;
    }
}
